package umuc.cmsc495.mach2;

import java.text.DecimalFormat;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnKeyListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;

/**
 * @author Michael Swann
 * @author Brett Hoyer
 */
public class Mach2ConvertActivity extends Activity implements OnItemSelectedListener, OnKeyListener {

	private Spinner	 spConvCat;      // Category Spinner
	private Spinner	 spInitType;     // Initial Type Spinner
	private Spinner	 spTargType;     // Target Type Spinner

	private EditText	initValue;      // Initial Value Box

	private int	     lastCatPos  = 0; // Last Position of the Category Spinner
	private int	     lastInitPos = 0; // Last Position of the Initial Type Spinner
	private int	     lastTargPos = 0; // Last Position of the Target Type Spinner

	private CalculationTask calcTask;       // Task for calculation thread

	private SharedPreferences prefs;
	private int sigFigInt;
	private int displayTypeInt;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		setup();
		initializePreferences();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.menu, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.options:
			startActivity(new Intent(this, Preferences.class));
			break;
		case R.id.about:
			showAboutInfo();
			break;
		}
		return true;
	}

	@Override
	public void onResume() {
		super.onResume();
	}

	@Override
	public void onStart() {
		super.onStart();
	}

	@Override
	public void onPause() {
		super.onPause();
	}

	@Override
	public void onStop() {
		super.onStop();
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
	}

	private void initializePreferences() {
		prefs = PreferenceManager
		.getDefaultSharedPreferences(Mach2ConvertActivity.this);
	}

	private String getSigFigPref() {
		return prefs.getString("significantFiguresList", "3");
	}

	private String getDisplayTypePref() {
		return prefs.getString("displayTypeList", "2");
	}

	private void showAboutInfo() {
		AlertDialog ad = new AlertDialog.Builder(this).create();
		ad.setMessage("Mach 2 Converter Designed by:\n" +
				"    Matthew Bland\n" +
				"    Jesse Furse\n" +
				"    Brett Hoyer\n" +
				"    Daniel Barker\n" +
				"    Michael Swann\n\n" +
				"V1.0\n" +
		"April 2012");
		ad.show();
	}

	/**
	 * Sets up the categories, initial, and target spinners and adds the
	 * onItemSelectedListeners. sets up the EditText Box and adds the
	 * onClickListener
	 */
	private void setup() {
		spConvCat = (Spinner) findViewById(R.id.spinnerCategory);
		spInitType = (Spinner) findViewById(R.id.spinnerInitialType);
		spTargType = (Spinner) findViewById(R.id.spinnerTargetType);

		initValue = (EditText) findViewById(R.id.editTextInitialValue);
		initValue.setText("");

		//Spinner Initialization
		ArrayAdapter<CharSequence> aCategories = ArrayAdapter.createFromResource(this,
				R.array.Categories, android.R.layout.simple_spinner_item);

		aCategories.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		spConvCat.setAdapter(aCategories);

		ArrayAdapter<CharSequence> aLength = ArrayAdapter.createFromResource(this, R.array.Length,
				android.R.layout.simple_spinner_item);

		aLength.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		spInitType.setAdapter(aLength);
		spTargType.setAdapter(aLength);
		spTargType.setSelection(1);

		spConvCat.setOnItemSelectedListener(this);
		spInitType.setOnItemSelectedListener(this);
		spTargType.setOnItemSelectedListener(this);

		initValue.setOnKeyListener(this);

		setResults("0");
	}

	/**
	 * Sets the Result Text box
	 * 
	 * @param result
	 *            value to be set
	 */
	private void setResults(String result) {
		TextView textViewResult = (TextView) findViewById(R.id.textViewResultNumber);
		textViewResult.setText(result);
	}

	/**
	 * Overrides the default action to be performed when a category is selected.
	 * Category: Changes Init/Type Spinners to proper category, clears result
	 * Init/Type: Calculates from current values
	 */
	public void onItemSelected(AdapterView<?> parentView, View selectedItemView,
			int position, long id) {
		if (parentView == spConvCat) { // Category Selected
			if (lastCatPos == position) { // No Change: Do Nothing
			} else { // Change: Switch Init/Targ Spinners to Proper Category based on Category Position
				lastCatPos = position;

				switch (position) {
				case 0:
					ArrayAdapter<CharSequence> aLength = ArrayAdapter.createFromResource(this,
							R.array.Length, android.R.layout.simple_spinner_item);

					aLength.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
					spInitType.setAdapter(aLength);
					spTargType.setAdapter(aLength);
					spTargType.setSelection(1);
					break;
				case 1:
					ArrayAdapter<CharSequence> aArea = ArrayAdapter.createFromResource(this,
							R.array.Area, android.R.layout.simple_spinner_item);

					aArea.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
					spInitType.setAdapter(aArea);
					spTargType.setAdapter(aArea);
					spTargType.setSelection(1);
					break;
				case 2:
					ArrayAdapter<CharSequence> aVolume = ArrayAdapter.createFromResource(this,
							R.array.Volume, android.R.layout.simple_spinner_item);

					aVolume.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
					spInitType.setAdapter(aVolume);
					spTargType.setAdapter(aVolume);
					spTargType.setSelection(1);
					break;
				case 3:
					ArrayAdapter<CharSequence> aCapacityDry = ArrayAdapter.createFromResource(this,
							R.array.CapacityDry, android.R.layout.simple_spinner_item);

					aCapacityDry.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
					spInitType.setAdapter(aCapacityDry);
					spTargType.setAdapter(aCapacityDry);
					spTargType.setSelection(1);
					break;
				case 4:
					ArrayAdapter<CharSequence> aCapacityWet = ArrayAdapter.createFromResource(this,
							R.array.CapacityWet, android.R.layout.simple_spinner_item);

					aCapacityWet.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
					spInitType.setAdapter(aCapacityWet);
					spTargType.setAdapter(aCapacityWet);
					spTargType.setSelection(1);
					break;
				case 5:
					ArrayAdapter<CharSequence> aMass = ArrayAdapter.createFromResource(this,
							R.array.Mass, android.R.layout.simple_spinner_item);

					aMass.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
					spInitType.setAdapter(aMass);
					spTargType.setAdapter(aMass);
					spTargType.setSelection(1);
					break;
				default:
					ArrayAdapter<CharSequence> aTemperature = ArrayAdapter.createFromResource(this,
							R.array.Temperature, android.R.layout.simple_spinner_item);

					aTemperature.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
					spInitType.setAdapter(aTemperature);
					spTargType.setAdapter(aTemperature);
					spTargType.setSelection(1);
					break;
				}

				if (initValue.getText().toString().equals("")){
					setResults("0"); // Clear Result
				} else {
					// Calculates Value if initial value has been previously entered
					startCalculationTask();
				}
			}
		} else if (parentView == spInitType) { // Initial Type Selected
			if (lastInitPos == position) { // No Change: Do Nothing
			} else { // Changed: Create Data from Current values and Calculate
				lastInitPos = position;
				startCalculationTask();
			}
		} else if (parentView == spTargType) { // Target Type Selected
			if (lastTargPos == position) { // No Change: Do Nothing
			} else { // Changed: Create Data from Current values and Calculate
				lastTargPos = position;
				startCalculationTask();
			}
		}
	}

	/**
	 * Overrides the default action to be performed when no category is
	 * selected.
	 */
	public void onNothingSelected(AdapterView<?> arg0) {
		// Empty
	}

	/**
	 * Overrides the default action to be performed when initial value is
	 * modified runs calculation when value is changed
	 */
	public boolean onKey(View v, int keyCode, KeyEvent event) {
		if (!initValue.getText().toString().equals(""))
			startCalculationTask();
		else
			setResults("0");
		return false;
	}

	/**
	 * @param str
	 *            String to check for double
	 * @return True: Is Double False: Not Double
	 */
	public static boolean isDouble(String str) {
		try {
			Double.parseDouble(str);
		} catch (Exception e) {
			return false;
		}

		return true;
	}

	/**
	 * Runs the AsyncTask to perform calculations and it is sychronized to avoid
	 * race conditions
	 */
	private synchronized void startCalculationTask() {
		EditText initText = (EditText) findViewById(R.id.editTextInitialValue);

		String temp = initText.getText().toString();
		int catPos = spConvCat.getSelectedItemPosition();
		int initTypePos = spInitType.getSelectedItemPosition();
		int targTypePos = spTargType.getSelectedItemPosition();

		Object[] calcParam = { temp, catPos, initTypePos, targTypePos };

		calcTask = new CalculationTask();
		calcTask.execute(calcParam);
	}

	/**
	 * Creates an AsyncTask to run alongside the UI < Params, Progress, Result >
	 * 
	 * @param CalcData
	 *            information for the calculation
	 * @param Void
	 *            Progress
	 * @param Double
	 *            value of result
	 */
	private class CalculationTask extends AsyncTask<Object[], Void, Double> {

		@Override
		protected Double doInBackground(Object[]... params) {

			double initValue = 0.0;
			Object[] calcParam = params[0];
			String temp = (String) calcParam[0];
			int catPos = (Integer) calcParam[1];
			int initTypePos = (Integer) calcParam[2];
			int targTypePos = (Integer) calcParam[3];

			if (isDouble(temp)) {
				initValue = Double.valueOf(temp);
			} else {
			}

			double result = 0.0;

			result = CalculationHandler.parseAndCalculate(catPos, initTypePos, targTypePos, initValue);

			return result;
		}

		/**
		 * On Post Execute, sets results TextView to returned result
		 */
		protected void onPostExecute(Double result) {
			sigFigInt = Integer.parseInt(getSigFigPref());
			displayTypeInt = Integer.parseInt(getDisplayTypePref());
			DecimalFormat df;
			String res = null;

			switch (displayTypeInt) {
			case 1:     //Scientific Notation
				switch (sigFigInt) {
				case 1:
					df = new DecimalFormat("@E0");
					break;
				case 2:
					df = new DecimalFormat("@@E0");
					break;
				case 3:
					df = new DecimalFormat("@@@E0");
					break;
				case 4:
					df = new DecimalFormat("@@@@E0");
					break;
				case 5:
					df = new DecimalFormat("@@@@@E0");
					break;
				case 6:
					df = new DecimalFormat("@@@@@@E0");
					break;
				default:
					df = new DecimalFormat("@@@E0");
					break;
				}
				res = df.format(result);
				break;
			case 2:     //Numeric with Scientific for very large or very small numbers
				switch (sigFigInt) {
				case 1:
					if (result > 1000000) {
						df = new DecimalFormat("@E0");
					} else if (result < 0.00001 && result > -0.00001) {
						df = new DecimalFormat("@E0");
					} else {
						df = new DecimalFormat("#,##@");
					}
					break;
				case 2:
					if (result > 1000000) {
						df = new DecimalFormat("@@E0");
					} else if (result < 0.00001 && result > -0.00001) {
						df = new DecimalFormat("@@E0");
					} else {
						df = new DecimalFormat("#,#@@");
					}
					break;
				case 3:
					if (result > 1000000) {
						df = new DecimalFormat("@@@E0");
					} else if (result < 0.00001 && result > -0.00001) {
						df = new DecimalFormat("@@@E0");
					} else {
						df = new DecimalFormat("#,@@@");
					}
					break;
				case 4:
					if (result > 1000000) {
						df = new DecimalFormat("@@@@E0");
					} else if (result < 0.00001 && result > -0.00001) {
						df = new DecimalFormat("@@@@E0");
					} else {
						df = new DecimalFormat("@,@@@");
					}
					break;
				case 5:
					if (result > 1000000) {
						df = new DecimalFormat("@@@@@E0");
					} else if (result < 0.00001 && result > -0.00001) {
						df = new DecimalFormat("@@@@@E0");
					} else {
						df = new DecimalFormat("@@,@@@");
					}
					break;
				case 6:
					if (result > 1000000) {
						df = new DecimalFormat("@@@@@@E0");
					} else if (result < 0.00001 && result > -0.00001) {
						df = new DecimalFormat("@@@@@@E0");
					} else {
						df = new DecimalFormat("@@@,@@@");
					}
					break;
				default:
					if (result > 1000000) {
						df = new DecimalFormat("@@@E0");
					} else if (result < 0.00001 && result > -0.00001) {
						df = new DecimalFormat("@@@E0");
					} else {
						df = new DecimalFormat("#,@@@");
					}
					break;
				}
				res = df.format(result);
				break;
			case 3:     //Label Notation
				switch (sigFigInt) {
				case 1:
					df = new DecimalFormat("@");
					break;
				case 2:
					df = new DecimalFormat("@@");
					break;
				case 3:
					df = new DecimalFormat("@@@");
					break;
				case 4:
					df = new DecimalFormat("@@@@");
					break;
				case 5:
					df = new DecimalFormat("@@@@@");
					break;
				case 6:
					df = new DecimalFormat("@@@@@@");
					break;
				default:
					df = new DecimalFormat("@@@");
					break;
				}

				if (result < 1000 && result > -1) {
					res = df.format(result).toString();
				} else if (result < 1000000) {
					res = df.format(result/1000).toString() + "Th";
				} else if (result < 1000000000) {
					res = df.format(result/1000000).toString() + "M";
				} else if (result/1000 < 1000000000) {
					res = df.format(result/1000000000).toString() + "B";
				} else if (result/1000000 < 1000000000) {
					res = df.format((result/1000000000)/1000).toString() + "T";
				} else if (result/1000000000 < 1000000000) {
					res = df.format((result/1000000000)/1000000).toString() + "Q";
				} else {
					res = "Too Large";
				}
				break;
			default:
				if (result > 1000000) {
					df = new DecimalFormat("@E0");
				} else if (result < 0.00001 && result > -0.00001) {
					df = new DecimalFormat("@E0");
				} else {
					df = new DecimalFormat("#,##@");
				}
				res = df.format(result);
				break;
			}

			setResults(res);
		}
	}

}